#include <http_serv_common.h>
#include <hash.h>
#ifdef _USE_HASH_TABLE
typedef	struct hash_node
{
	void *key;
	void *value;
	uint32_t val_len;
	struct hash_node *prev;
	struct hash_node *next;
} hash_node_t;

struct hash
{
	uint32_t buckets;
	hashfunc_t hash_func;
	//hash表中所存放的链表的首地址
	hash_node_t **nodes;
};
static uint32_t max_prime_num = 0;

inline uint32_t
get_max_prime_num(void)
{
	return max_prime_num;
}

hash_t*
hash_alloc(uint32_t buckets, hashfunc_t hash_func)
{
	//分配一个空间，建立hash的桶大小
	hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
	hash->buckets = buckets;
	hash->hash_func = hash_func;
	int size = buckets * sizeof(hash_node_t *);
	hash->nodes = (hash_node_t **)malloc(size);
	memset(hash->nodes,0,size);
	max_prime_num = cacl_max_prime(buckets);
	return hash;
}

void
hash_list_free(hash_node_t *h_n)
{
	if(NULL == h_n) {
		return;
	}
	hash_node_t *tmp;
	while(NULL != h_n) {
		tmp = h_n;
		h_n = h_n->next;
		free(tmp->key);
		#ifdef _USE_MMAP
		munmap(tmp->value,tmp->val_len);
		#else
		free(tmp->value);
		#endif
		free(tmp);
	}
}

void
hash_free(hash_t *h_t)
{
	//将整个hash表进行释放
	int i;
	for(i = 0;i < h_t->buckets;++i) {
		hash_list_free(h_t->nodes[i]);
	}
	free(h_t);
}

static hash_node_t**
hash_get_bucket(hash_t *hash, void *key)
{
	//找到桶号
	uint32_t bucket = hash->hash_func(hash->buckets,key);
	if(bucket >= hash->buckets) {
		fprintf(stderr,"bad bucket lookup\n");
		exit(EXIT_FAILURE);
	}
	return &(hash->nodes[bucket]);
}
static hash_node_t*
hash_get_node_by_key(hash_t *hash, void *key, unsigned int key_size)
{
	hash_node_t **bucket = hash_get_bucket(hash,key);
	hash_node_t *node = *bucket;
	if(NULL == node) {
		return NULL;
	}
	while(NULL != node && 0 != memcmp(node->key,key,key_size)) {
		node = node->next;
	}
	return node;
}

void*
hash_lookup_entry(hash_t *hash, void* key, 
	uint32_t key_size, uint32_t *val_len)
{
	//给定关键码，找到对应的项，然后到链表中进行查找。
	hash_node_t *node = hash_get_node_by_key(hash,key,key_size);
	if(NULL == node) {
		return NULL;
	}
	*val_len = node->val_len;
	return node->value;
}
void
hash_add_entry(hash_t *hash, void *key, uint32_t key_size,
						void *value, uint32_t value_size)
{
	//判断数据项是否存在，存在就不需要添加了
	uint32_t val_len;
	if(NULL != hash_lookup_entry(hash,key,
					key_size,&val_len)) {
		fprintf(stderr,"duplicate hash key\n");
		return;
	}

	hash_node_t *node = \
		(hash_node_t *)malloc(sizeof(hash_node_t));
	node->prev = NULL;
	node->next = NULL;
	node->key = malloc(key_size);
	memcpy(node->key,key,key_size);
	#ifdef _USE_MMAP
	node->value = value;
	#else
	node->value = malloc(value_size);
	memcpy(node->value,value,value_size);
	#endif
	node->val_len = value_size;

	hash_node_t **bucket = hash_get_bucket(hash,key);
	if(NULL == *bucket) {
		*bucket = node;
	} else {
		node->next = *bucket;
		(*bucket)->prev = node;
		*bucket = node;
	}
}
void
hash_free_entry(hash_t *hash, void *key, uint32_t key_size)
{
	hash_node_t *node = hash_get_node_by_key(hash,key,key_size);
	if(NULL == node) {
		return;
	}
	free(node->key);
	free(node->value);
	if(NULL != node->prev) {
		node->prev->next = node->next;
	} else {
		//说明是头指针要修改头部指向
		hash_node_t **bucket = hash_get_bucket(hash,key);
		*bucket = node->next;
	}
	if(NULL != node->next) {
		node->next->prev = node->prev;
	}
	free(node);
}

//一个不超过max_limit的最大质数
#define	ARR_LEN(a)	(sizeof(a) / sizeof(a[0]))

static bool
is_prime(int num)
{
	if(2 == num || 3 == num \
				|| 5 == num) {
		return true;
	}
	if(0 == num % 2 || 0 == num % 3 \
					|| 0 == num % 5 \
					|| 1 == num) {
		return false;
	}
	uint32_t c = 7;
	int maxc = (int)(sqrt(num));
	int i;
	const uint32_t prime_chk_num[8] = {
		4,2,4,2,4,6,2,6
	};
	while(c <= maxc)
	{
		for(i = 0;i < ARR_LEN(prime_chk_num);++i) {
			if(0 == num % c)
				return false;
			c += prime_chk_num[i];
		}
		return true;
	}
	return false;
}

uint32_t
cacl_max_prime(uint32_t max_limit)
{
	while(!is_prime(max_limit--));
	return ++max_limit;
}

#endif
